package org.xx.armory.swing.components;

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.Component;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.geom.Rectangle2D;

import static org.apache.commons.lang3.StringUtils.trimToEmpty;
import static org.xx.armory.commons.SysUtils.stringEquals;
import static org.xx.armory.swing.ComponentUtils.combineBorders;
import static org.xx.armory.swing.ComponentUtils.lighterColor;

public class InputField
        extends JFormattedTextField {
    private static final int EMPTY_GAP = 2;
    private String prefix;
    private String suffix;
    private Border prefixSuffixBorder;

    public InputField(
            String prefix,
            String suffix,
            JFormattedTextField.AbstractFormatter formatter
    ) {
        super(formatter);

        this.prefix = trimToEmpty(prefix);
        this.suffix = trimToEmpty(suffix);

        this.prefixSuffixBorder = new PrefixSuffixBorder();

        // 构造函数的结束必须调用 updateUI()，强制调用 setBorder方法。
        updateUI();
    }

    public void setPrefix(
            String prefix
    ) {
        prefix = trimToEmpty(prefix);

        if (!stringEquals(prefix, this.prefix)) {
            revalidate();
            repaint();
        }
    }

    public void setSuffix(
            String suffix
    ) {
        suffix = trimToEmpty(suffix);

        if (!stringEquals(suffix, this.suffix)) {
            revalidate();
            repaint();
        }
    }

    @Override
    public void setBorder(
            Border border
    ) {
        super.setBorder(combineBorders(border, this.prefixSuffixBorder));
    }

    private class PrefixSuffixBorder
            implements Border {
        /**
         * {@inheritDoc}
         */
        @Override
        public void paintBorder(
                Component c,
                Graphics g,
                int x,
                int y,
                int width,
                int height
        ) {
            final Graphics2D g2d = (Graphics2D) g;
            final FontMetrics fm = g2d.getFontMetrics();
            Rectangle2D rect;

            g.setColor(lighterColor(getForeground()));

            if (!prefix.isEmpty()) {
                rect = fm.getStringBounds(prefix, g2d);
                y += (height - (int) rect.getHeight()) / 2 + fm.getAscent();
                g.drawString(prefix, x, y);
            }

            if (!suffix.isEmpty()) {
                rect = fm.getStringBounds(suffix, g2d);
                x += width - (int) rect.getWidth();
                y += (height - (int) rect.getHeight()) / 2 + fm.getAscent();
                g.drawString(suffix, x, y);
            }
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Insets getBorderInsets(
                Component c
        ) {
            final int prefixWidth, suffixWidth;
            if (!prefix.isEmpty()) {
                prefixWidth = (int) getFontMetrics(getFont()).getStringBounds(prefix, null).getWidth() + EMPTY_GAP;
            } else {
                prefixWidth = 0;
            }
            if (!suffix.isEmpty()) {
                suffixWidth = (int) getFontMetrics(getFont()).getStringBounds(suffix, null).getWidth() + EMPTY_GAP;
            } else {
                suffixWidth = 0;
            }

            return new Insets(0, prefixWidth, 0, suffixWidth);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public boolean isBorderOpaque() {
            return false;
        }
    }
}
